home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 31 / Amiga Format CD31 (1998-09-02)(Future Publishing)(GB)(Track 1 of 2)[!][issue 1998-10].iso / -seriously_amiga- / sound / ahi / developer / filesave / filesave.c < prev    next >
C/C++ Source or Header  |  1998-07-16  |  29KB  |  1,259 lines

  1.  
  2. #define NO_PROTOS
  3. #define NO_SAS_PRAGMAS
  4. #include <iffp/8svx.h>
  5. #undef NO_PROTOS
  6. #undef NO_SAS_PRAGMAS
  7.  
  8. #include <exec/exec.h>
  9. #include <devices/ahi.h>
  10. #include <dos/dos.h>
  11. #include <dos/dostags.h>
  12. #include <graphics/gfxbase.h>
  13. #include <libraries/ahi_sub.h>
  14. #include <libraries/asl.h>
  15. #include <datatypes/datatypes.h>
  16. #include <datatypes/soundclass.h>
  17. #include <proto/asl.h>
  18. #include <proto/exec.h>
  19. #include <proto/dos.h>
  20. #include <proto/intuition.h>
  21. #include <proto/utility.h>
  22. #include <proto/datatypes.h>
  23. #include <proto/ahi_sub.h>
  24. #include <stdlib.h>
  25. #include "filesave.h"
  26.  
  27. #define dd ((struct filesave *) AudioCtrl->ahiac_DriverData)
  28.  
  29. #define SAVEBUFFERSIZE 100000   // in samples (min)
  30. #define RECBUFFERSIZE  10000    // in samples
  31.  
  32. struct AIFCheader {
  33.   ULONG                 FORMid;
  34.   ULONG                 FORMsize;
  35.   ULONG                 AIFCid;
  36.  
  37.   ULONG                 FVERid;
  38.   ULONG                 FVERsize;
  39.   FormatVersionHeader   FVERchunk;
  40.  
  41.   ULONG                 COMMid;
  42.   ULONG                 COMMsize;
  43.   ExtCommonChunk        COMMchunk;
  44.  
  45.   ULONG                 SSNDid;
  46.   ULONG                 SSNDsize;
  47.   SampledSoundHeader    SSNDchunk;
  48. };
  49.  
  50. struct AIFFheader {
  51.   ULONG                 FORMid;
  52.   ULONG                 FORMsize;
  53.   ULONG                 AIFFid;
  54.  
  55.   ULONG                 COMMid;
  56.   ULONG                 COMMsize;
  57.   CommonChunk           COMMchunk;
  58.  
  59.   ULONG                 SSNDid;
  60.   ULONG                 SSNDsize;
  61.   SampledSoundHeader    SSNDchunk;
  62. };
  63.  
  64. struct EIGHTSVXheader {
  65.   ULONG                 FORMid;
  66.   ULONG                 FORMsize;
  67.   ULONG                 EIGHTSVXid;
  68.  
  69.   ULONG                 VHDRid;
  70.   ULONG                 VHDRsize;
  71.   Voice8Header          VHDRchunk;
  72.  
  73.   ULONG                 BODYid;
  74.   ULONG                 BODYsize;
  75. };
  76.  
  77. extern char __far _LibID[];
  78. extern char __far _LibName[];
  79.  
  80. extern void KPrintF(char *fmt,...);
  81.  
  82. #define FREQUENCIES 23
  83. const ULONG  frequency[FREQUENCIES] =
  84. {
  85.   5513,
  86.   6615,
  87.   8000,     // µ- and A-Law
  88.   9600,     // DAT/5
  89.   11025,    // CD/4
  90.   12000,    // DAT/4
  91.   14700,    // CD/3
  92.   16000,    // DAT/3
  93.   17640,    // CD/2.5
  94.   18900,
  95.   19200,    // DAT/2.5
  96.   22050,    // CD/2
  97.   24000,    // DAT/2
  98.   27429,
  99.   29400,    // CD/1.5
  100.   32000,    // DAT/1.5
  101.   33075,
  102.   37800,
  103.   44056,    // Some kind of video rate
  104.   44100,    // CD
  105.   48000,    // DAT
  106.   88200,    // CD*2
  107.   96000     // DAT*2
  108. };
  109.  
  110. extern void SlaveEntry(void);
  111. extern void RecSlaveEntry(void);
  112. void ulong2extended (ULONG in, extended *ex);
  113.  
  114. struct DosLibrary     *DOSBase        = NULL;
  115. struct Library        *UtilityBase    = NULL;
  116. struct Library        *AslBase        = NULL;
  117. struct IntuitionBase  *IntuitionBase  = NULL;
  118. struct Library        *AHIsubBase     = NULL;
  119. struct Library        *DataTypesBase  = NULL;
  120. struct GfxBase        *GfxBase        = NULL;
  121.  
  122. int  __saveds __asm __UserLibInit (register __a6 struct Library *libbase)
  123. {
  124.   AHIsubBase = libbase;
  125.  
  126.   if(!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  127.   {
  128.     Alert(AN_Unknown|AG_OpenLib|AO_DOSLib);
  129.     return 1;
  130.   }
  131.  
  132.   if(!(GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 37)))
  133.   {
  134.     Alert(AN_Unknown|AG_OpenLib|AO_GraphicsLib);
  135.     return 1;
  136.   }
  137.  
  138.   if(!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 37)))
  139.   {
  140.     Alert(AN_Unknown|AG_OpenLib|AO_Intuition);
  141.     return 1;
  142.   }
  143.  
  144.   if(!(UtilityBase = OpenLibrary("utility.library", 37)))
  145.   {
  146.     Alert(AN_Unknown|AG_OpenLib|AO_UtilityLib);
  147.     return 1;
  148.   }
  149.  
  150. // Don't fail if these ones don't open!
  151.  
  152.   if(!(AslBase = OpenLibrary("asl.library", 37)))
  153.   {
  154.     struct EasyStruct req = {
  155.         sizeof (struct EasyStruct), 0, _LibName,
  156.         "Cannot open 'asl.library' v37", "OK"};
  157.  
  158.        EasyRequest( NULL, &req, NULL, NULL );
  159.   }
  160.  
  161.   DataTypesBase = OpenLibrary("datatypes.library",39);
  162.  
  163.   return 0;
  164. }
  165.  
  166. void __saveds __asm __UserLibCleanup (register __a6 struct Library *libbase)
  167. {
  168.   if(AslBase)       { CloseLibrary(AslBase); AslBase = NULL; }
  169.   if(DOSBase)       { CloseLibrary((struct Library *)DOSBase); DOSBase = NULL; }
  170.   if(GfxBase)       { CloseLibrary((struct Library *)GfxBase); GfxBase = NULL; }
  171.   if(IntuitionBase) { CloseLibrary((struct Library *)IntuitionBase); IntuitionBase = NULL; }
  172.   if(UtilityBase)   { CloseLibrary(UtilityBase); UtilityBase = NULL; }
  173.   if(DataTypesBase) { CloseLibrary(DataTypesBase); DataTypesBase = NULL; }
  174. }
  175.  
  176. ULONG __asm __saveds intAHIsub_AllocAudio(
  177.     register __a1 struct TagItem *tagList,
  178.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  179. {
  180.   char *ext = "";
  181.  
  182.   if(AslBase == NULL)
  183.   {
  184.     return AHISF_ERROR;
  185.   }
  186.  
  187.   if(AudioCtrl->ahiac_DriverData = AllocVec(sizeof(struct filesave),MEMF_CLEAR))
  188.   {
  189.     dd->fs_AHIsubBase       = AHIsubBase;
  190.     dd->fs_DisableSignal    = -1;
  191.     dd->fs_EnableSignal     = -1;
  192.     dd->fs_SlaveSignal      = -1;
  193.     dd->fs_MasterSignal     = AllocSignal(-1);
  194.     dd->fs_MasterTask       = (struct Process *) FindTask(NULL);
  195.     dd->fs_RecSlaveSignal   = -1;
  196.     dd->fs_RecMasterSignal  = AllocSignal(-1);
  197.   }
  198.   else
  199.   {
  200.     return AHISF_ERROR;
  201.   }
  202.  
  203.   if((dd->fs_MasterSignal == -1) || (dd->fs_RecMasterSignal == -1))
  204.   {
  205.     return AHISF_ERROR;
  206.   }
  207.  
  208.   dd->fs_Format = GetTagData(AHIDB_FileSaveFormat, FORMAT_8SVX, tagList);
  209.  
  210.   switch(dd->fs_Format)
  211.   {
  212.     case FORMAT_8SVX:
  213.       ext = ".8SVX";
  214.       break;
  215.  
  216.     case FORMAT_AIFF:
  217.       ext = ".AIFF";
  218.       break;
  219.  
  220.     case FORMAT_AIFC:
  221.       ext = ".AIFC";
  222.       break;
  223.  
  224.     case FORMAT_S16:
  225.       break;
  226.  
  227.     default:
  228.       break;
  229.   }
  230.  
  231.   if(!(dd->fs_FileReq = AllocAslRequestTags(ASL_FileRequest,
  232.       ASLFR_InitialFile,  ext,
  233.       ASLFR_DoSaveMode,   TRUE,
  234.       ASLFR_RejectIcons,  TRUE,
  235.       ASLFR_TitleText,    _LibID,
  236.       TAG_DONE)))
  237.   {
  238.     return AHISF_ERROR;
  239.   }
  240.  
  241.   if(!(dd->fs_RecFileReq = AllocAslRequestTags(ASL_FileRequest,
  242.       ASLFR_RejectIcons,  TRUE,
  243.       ASLFR_TitleText,    "Select a sound sample",
  244.       TAG_DONE)))
  245.   {
  246.     return AHISF_ERROR;
  247.   }
  248.  
  249.   return AHISF_KNOWHIFI|AHISF_KNOWSTEREO|AHISF_CANRECORD|AHISF_MIXING|AHISF_TIMING;
  250. }
  251.  
  252. void __asm __saveds intAHIsub_FreeAudio(
  253.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  254. {
  255.   if(AudioCtrl->ahiac_DriverData)
  256.   {
  257.     FreeAslRequest(dd->fs_FileReq);
  258.     FreeAslRequest(dd->fs_RecFileReq);
  259.     FreeSignal(dd->fs_MasterSignal);
  260.     FreeSignal(dd->fs_RecMasterSignal);
  261.     FreeVec(AudioCtrl->ahiac_DriverData);
  262.     AudioCtrl->ahiac_DriverData = NULL;
  263.   }
  264. }
  265.  
  266. ULONG __asm __saveds intAHIsub_Start(
  267.     register __d0 ULONG Flags,
  268.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  269. {
  270.  
  271.   AHIsub_Stop(Flags, AudioCtrl);
  272.  
  273.   if(Flags & AHISF_PLAY)
  274.   {
  275.     ULONG savebufferlength;
  276.  
  277.     if(!(dd->fs_MixBuffer = AllocVec(AudioCtrl->ahiac_BuffSize, MEMF_ANY)))
  278.       return AHIE_NOMEM;
  279.  
  280.     dd->fs_SaveBufferSize = AudioCtrl->ahiac_MaxBuffSamples;
  281.  
  282.     // S16 has two buffers (L/R) instead
  283.     if((AudioCtrl->ahiac_Flags & AHIACF_STEREO) && dd->fs_Format != FORMAT_S16)
  284.     {
  285.       dd->fs_SaveBufferSize <<=1;
  286.     }
  287.  
  288.     if(dd->fs_SaveBufferSize < SAVEBUFFERSIZE)
  289.     {
  290.       dd->fs_SaveBufferSize = SAVEBUFFERSIZE;
  291.     }
  292.  
  293.     savebufferlength = dd->fs_SaveBufferSize;
  294.  
  295.  
  296.     switch(dd->fs_Format)
  297.     {
  298.       case FORMAT_8SVX:
  299.         break;
  300.  
  301.       case FORMAT_AIFF:
  302.         savebufferlength <<= 1;
  303.         break;
  304.  
  305.       case FORMAT_AIFC:
  306.         savebufferlength <<= 1;
  307.         break;
  308.  
  309.       case FORMAT_S16:
  310.         savebufferlength <<= 1;
  311.         break;
  312.  
  313.       default:
  314.         break;
  315.     }
  316.  
  317.  
  318.     if(!(dd->fs_SaveBuffer = AllocVec(savebufferlength, MEMF_ANY)))
  319.     {
  320.       return AHIE_NOMEM;
  321.     }
  322.  
  323.     if ((AudioCtrl->ahiac_Flags & AHIACF_STEREO) && dd->fs_Format == FORMAT_S16)
  324.     {
  325.       if(!(dd->fs_SaveBuffer2 = AllocVec(savebufferlength, MEMF_ANY)))
  326.       {
  327.         return AHIE_NOMEM;
  328.       }
  329.     }
  330.  
  331.     if(AslRequestTags(dd->fs_FileReq,TAG_DONE))
  332.     {
  333.  
  334.       Forbid();
  335.  
  336.       if(dd->fs_SlaveTask = CreateNewProcTags(
  337.           NP_Entry,     SlaveEntry,
  338.           NP_Name,      _LibName,
  339.           NP_Priority,  -1,               // It's a number cruncher...
  340.           NP_StackSize, 10000,
  341.           TAG_DONE))
  342.       {
  343.         dd->fs_SlaveTask->pr_Task.tc_UserData = AudioCtrl;
  344.       }
  345.  
  346.       Permit();
  347.  
  348.       if(dd->fs_SlaveTask)
  349.       {
  350.         Wait(1L<<dd->fs_MasterSignal);  // Wait for slave to come alive
  351.         if(dd->fs_SlaveTask == NULL)    // Is slave alive or dead?
  352.         {
  353.           return AHIE_UNKNOWN;
  354.         }
  355.       }
  356.       else
  357.       {
  358.         return AHIE_NOMEM;
  359.       }
  360.     }
  361.     else
  362.     {
  363.       if(IoErr())
  364.       {
  365.         return AHIE_NOMEM;    //error occured
  366.       }
  367.       else
  368.       {
  369.         return AHIE_ABORTED;  //requester cancelled
  370.       }
  371.     }
  372.   }
  373.  
  374.   if(Flags & AHISF_RECORD)
  375.   {
  376.     if(!(dd->fs_RecBuffer = AllocVec(RECBUFFERSIZE*4,MEMF_ANY)))
  377.     {
  378.       return AHIE_NOMEM;
  379.     }
  380.  
  381.     if(AslRequestTags(dd->fs_RecFileReq,TAG_DONE))
  382.     {
  383.       Delay(TICKS_PER_SECOND);         // Wait for window to close etc...
  384.  
  385.       Forbid();
  386.  
  387.       if(dd->fs_RecSlaveTask = CreateNewProcTags(
  388.           NP_Entry,     RecSlaveEntry,
  389.           NP_Name,      _LibName,
  390.           NP_Priority,  1,               // Make it steady...
  391.           TAG_DONE))
  392.       {
  393.         dd->fs_RecSlaveTask->pr_Task.tc_UserData = AudioCtrl;
  394.       }
  395.  
  396.       Permit();
  397.  
  398.       if(dd->fs_RecSlaveTask)
  399.       {
  400.         Wait(1L<<dd->fs_RecMasterSignal);  // Wait for slave to come alive
  401.         if(dd->fs_RecSlaveTask == NULL)    // Is slave alive or dead?
  402.         {
  403.           return AHIE_UNKNOWN;
  404.         }
  405.       }
  406.       else
  407.       {
  408.         return AHIE_NOMEM;
  409.       }
  410.     }
  411.     else
  412.     {
  413.       if(IoErr())
  414.       {
  415.         return AHIE_NOMEM;    //error occured
  416.       }
  417.       else
  418.       {
  419.         return AHIE_ABORTED;  //requester cancelled
  420.       }
  421.     }
  422.   }
  423.  
  424.   return AHIE_OK;
  425. }
  426.  
  427.  
  428. void __asm __saveds intAHIsub_Update(
  429.     register __d0 ULONG Flags,
  430.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  431. {
  432. }
  433.  
  434.  
  435. void __asm __saveds intAHIsub_Stop(
  436.     register __d0 ULONG Flags,
  437.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  438. {
  439.   if(Flags & AHISF_PLAY)
  440.   {
  441.     if(dd->fs_SlaveTask)
  442.     {
  443.       if(dd->fs_SlaveSignal != -1)
  444.       {
  445.         Signal((struct Task *)dd->fs_SlaveTask,1L<<dd->fs_SlaveSignal); // Kill him!
  446.       }
  447.       Wait(1L<<dd->fs_MasterSignal);  // Wait for slave to die
  448.     }
  449.     FreeVec(dd->fs_MixBuffer);
  450.     dd->fs_MixBuffer = NULL;
  451.     FreeVec(dd->fs_SaveBuffer);
  452.     FreeVec(dd->fs_SaveBuffer2);
  453.     dd->fs_SaveBuffer = NULL;
  454.     dd->fs_SaveBuffer2 = NULL;
  455.   }
  456.  
  457.   if(Flags & AHISF_RECORD)
  458.   {
  459.     if(dd->fs_RecSlaveTask)
  460.     {
  461.       if(dd->fs_RecSlaveSignal != -1)
  462.       {
  463.         Signal((struct Task *)dd->fs_RecSlaveTask,1L<<dd->fs_RecSlaveSignal); // Kill him!
  464.       }
  465.       Wait(1L<<dd->fs_RecMasterSignal);  // Wait for slave to die
  466.     }
  467.     FreeVec(dd->fs_RecBuffer);
  468.     dd->fs_RecBuffer = NULL;
  469.   }
  470. }
  471.  
  472.  
  473.  
  474. LONG __asm __saveds intAHIsub_GetAttr(
  475.     register __d0 ULONG Attribute,
  476.     register __d1 LONG Argument,
  477.     register __d2 LONG Default,
  478.     register __a1 struct TagItem *tagList,
  479.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
  480. {
  481.   int i;
  482.  
  483.   switch(Attribute)
  484.   {
  485.     case AHIDB_Bits:
  486.       switch (GetTagData(AHIDB_FileSaveFormat,FORMAT_8SVX,tagList))
  487.       {
  488.         case FORMAT_8SVX:
  489.           return 8;
  490.  
  491.         case FORMAT_AIFF:
  492.           return 16;
  493.  
  494.         case FORMAT_AIFC:
  495.           return 16;
  496.  
  497.         case FORMAT_S16:
  498.           return 16;
  499.  
  500.         default:
  501.           return Default;
  502.       }
  503.  
  504.     case AHIDB_Frequencies:
  505.       return FREQUENCIES;
  506.  
  507.     case AHIDB_Frequency: // Index->Frequency
  508.       return (LONG) frequency[Argument];
  509.  
  510.     case AHIDB_Index: // Frequency->Index
  511.       if(Argument <= frequency[0])
  512.       {
  513.         return 0;
  514.       }
  515.       if(Argument >= frequency[FREQUENCIES-1])
  516.       {
  517.         return FREQUENCIES-1;
  518.       }
  519.       for(i = 1;i<FREQUENCIES;i++)
  520.       {
  521.         if(frequency[i]>Argument)
  522.         {
  523.           if( (Argument-frequency[i-1]) < (frequency[i]-Argument) )
  524.           {
  525.             return i-1;
  526.           }
  527.           else
  528.           {
  529.             return i;
  530.           }
  531.         }
  532.       }
  533.       return 0;  // Will not happen
  534.  
  535.     case AHIDB_Author:
  536.       return (LONG) "Martin 'Leviticus' Blom";
  537.  
  538.     case AHIDB_Copyright:
  539.       return (LONG) "Public Domain";
  540.  
  541.     case AHIDB_Version:
  542.       return (LONG) _LibID;
  543.  
  544.     case AHIDB_Record:
  545.       return TRUE;
  546.  
  547.     case AHIDB_FullDuplex:
  548.       return TRUE;
  549.  
  550.     case AHIDB_MaxRecordSamples:
  551.       return RECBUFFERSIZE;
  552.  
  553.     case AHIDB_Realtime:
  554.       return FALSE;
  555.  
  556.     case AHIDB_Inputs:
  557.       return 1;
  558.  
  559.     case AHIDB_Input:
  560.       return (LONG) "File";    // We have only one input!
  561.  
  562.     case AHIDB_Outputs:
  563.       return 1;
  564.  
  565.     case AHIDB_Output:
  566.       return (LONG) "File";    // We have only one output!
  567.  
  568.     default:
  569.       return Default;
  570.   }
  571. }
  572.  
  573.  
  574. ULONG __asm __saveds intAHIsub_HardwareControl(
  575.     register __d0 ULONG attribute,
  576.     register __d1 LONG argument,
  577.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  578. {
  579.   return NULL;
  580. }
  581.  
  582. /*
  583. ** Unused LVOs follows...
  584. */
  585.  
  586. ULONG __asm __saveds intAHIsub_SetVol(
  587.     register __d0 UWORD channel,
  588.     register __d1 Fixed volume,
  589.     register __d2 sposition pan,
  590.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl,
  591.     register __d3 ULONG Flags)
  592. {
  593.   return AHIS_UNKNOWN;
  594. }
  595.  
  596. ULONG __asm __saveds intAHIsub_SetFreq(
  597.     register __d0 UWORD channel,
  598.     register __d1 ULONG freq,
  599.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl,
  600.     register __d2 ULONG flags )
  601. {
  602.   return AHIS_UNKNOWN;
  603. }
  604.  
  605. ULONG __asm __saveds intAHIsub_SetSound(
  606.     register __d0 UWORD channel,
  607.     register __d1 UWORD sound,
  608.     register __d2 ULONG offset,
  609.     register __d3 LONG length,
  610.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl,
  611.     register __d4 ULONG flags )
  612. {
  613.   return AHIS_UNKNOWN;
  614. }
  615.  
  616.  
  617. ULONG __asm __saveds intAHIsub_SetEffect (
  618.     register __a0 APTR effect,
  619.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  620. {
  621.   return AHIS_UNKNOWN;
  622. }
  623.  
  624. ULONG __asm __saveds intAHIsub_LoadSound(
  625.     register __d0 UWORD sound,
  626.     register __d1 ULONG type,
  627.     register __a0 APTR info,
  628.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  629. {
  630.   return AHIS_UNKNOWN;
  631. }
  632.  
  633. ULONG __asm __saveds intAHIsub_UnloadSound(
  634.     register __d0 UWORD sound,
  635.     register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
  636. {
  637.   return AHIS_UNKNOWN;
  638. }
  639.  
  640.  
  641.  
  642. /*
  643. ** The slave process
  644. */
  645.  
  646. void __asm __saveds SlaveTask(register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
  647. // SlaveEntry() will set up register a2 and a6 for us.
  648. {
  649.   struct EIGHTSVXheader EIGHTSVXheader = // All NULLs will be filled later.
  650.   { 
  651.     ID_FORM, NULL, ID_8SVX,
  652.     ID_VHDR, sizeof(Voice8Header),
  653.     {
  654.       NULL,
  655.       0,
  656.       0,
  657.       NULL,
  658.       1,
  659.       sCmpNone,
  660.       0x10000
  661.     },
  662.     ID_BODY, NULL
  663.   };
  664.  
  665.   struct AIFFheader AIFFheader = // All NULLs will be filled later.
  666.   { 
  667.     ID_FORM, NULL, ID_AIFF,
  668.     ID_COMM, sizeof(CommonChunk),
  669.     {
  670.       NULL,
  671.       NULL,
  672.       16,
  673.       {
  674.         NULL
  675.       }
  676.     },
  677.     ID_SSND, NULL,
  678.     {
  679.       0,
  680.       0
  681.     }
  682.   };
  683.  
  684.   struct AIFCheader AIFCheader = // All NULLs will be filled later.
  685.   { 
  686.     ID_FORM, NULL, ID_AIFC,
  687.     ID_FVER, sizeof(FormatVersionHeader), 
  688.     {
  689.       AIFCVersion1
  690.     },
  691.     ID_COMM, sizeof(ExtCommonChunk),
  692.     {
  693.       NULL,
  694.       NULL,
  695.       16,
  696.       {
  697.         NULL
  698.       },
  699.       NO_COMPRESSION,
  700.       sizeof("not compressed") - 1,
  701.       'n','o','t',' ','c','o','m','p','r','e','s','s','e','d'
  702.     },
  703.     ID_SSND, NULL,
  704.     {
  705.       0,
  706.       0
  707.     }
  708.   };
  709.  
  710.   struct STUDIO16FILE S16header = // All NULLs will be filled later.
  711.   {
  712.     S16FID,
  713.     NULL,
  714.     S16FINIT,
  715.     S16_VOL_0,
  716.     0,
  717.     0,
  718.     NULL,
  719.     0,
  720.     0,
  721.     NULL,
  722.     NULL,
  723.     0,
  724.     NULL,
  725.     0,
  726.     {
  727.       0
  728.     }
  729.   };
  730.  
  731.   struct EasyStruct req =
  732.   {
  733.     sizeof (struct EasyStruct),
  734.     0,
  735.     _LibID,
  736.     "Rendering finished.\nTo futher improve the quality of the sample,\n"
  737.     "you can raise the volume to %ld%%%sand render again.",
  738.     "OK",
  739.   };
  740.  
  741.   BPTR lock = NULL,cd = NULL,file = NULL, file2 = NULL;
  742.   ULONG signals, i, maxVolume = 0, samples, length;
  743.   ULONG offset = 0, bytesInBuffer = 0, samplesWritten = 0, bytesWritten = 0;
  744.  
  745. // We cannot handle stereo 8SVXs!
  746.   if( (dd->fs_Format == FORMAT_8SVX) &&
  747.       (AudioCtrl->ahiac_Flags & AHIACF_STEREO) )
  748.   {
  749.     goto quit;
  750.   }
  751.  
  752.   if((dd->fs_DisableSignal = AllocSignal(-1)) == -1)
  753.   {
  754.     goto quit;
  755.   }
  756.   if((dd->fs_EnableSignal = AllocSignal(-1)) == -1)
  757.   {
  758.     goto quit;
  759.   }
  760.   if((dd->fs_SlaveSignal = AllocSignal(-1)) == -1)
  761.   {
  762.     goto quit;
  763.   }
  764.  
  765.   if(!(lock = Lock(dd->fs_FileReq->fr_Drawer, ACCESS_READ)))
  766.   {
  767.     goto quit;
  768.   }
  769.  
  770.   cd = CurrentDir(lock);
  771.  
  772.   switch(dd->fs_Format)
  773.   {
  774.     case FORMAT_8SVX:
  775.       if(!(file = Open(dd->fs_FileReq->fr_File, MODE_NEWFILE))) goto quit;
  776.       Write(file, &EIGHTSVXheader, sizeof EIGHTSVXheader);
  777.       break;
  778.  
  779.     case FORMAT_AIFF:
  780.       if(!(file = Open(dd->fs_FileReq->fr_File, MODE_NEWFILE))) goto quit;
  781.       Write(file, &AIFFheader, sizeof AIFFheader);
  782.       break;
  783.  
  784.     case FORMAT_AIFC:
  785.       if(!(file = Open(dd->fs_FileReq->fr_File, MODE_NEWFILE))) goto quit;
  786.       Write(file, &AIFCheader, sizeof AIFCheader);
  787.       break;
  788.  
  789.     case FORMAT_S16:
  790.       if (AudioCtrl->ahiac_Flags & AHIACF_STEREO)
  791.       {
  792.         char filename[256];
  793.         int len;
  794.  
  795.         strncpy (filename, dd->fs_FileReq->fr_File, sizeof(filename) - 3);
  796.         len = strlen(filename);
  797.  
  798.         if(len >= 2 && filename[len - 2] == '_'
  799.            && (filename[len - 1] == 'L' || filename[len - 1] == 'R'))
  800.         {
  801.           filename[len - 1] = 'L';
  802.         }
  803.         else
  804.         {
  805.           strcat (filename, "_L");
  806.         }
  807.  
  808.         if(!(file = Open(filename, MODE_NEWFILE))) goto quit;
  809.  
  810.         filename[strlen(filename) - 1] = 'R';
  811.         if(!(file2 = Open(filename, MODE_NEWFILE))) goto quit;
  812.  
  813.         Write(file, &S16header, sizeof S16header);
  814.         Write(file2, &S16header, sizeof S16header);
  815.       }
  816.       else
  817.       {
  818.         if(!(file = Open(dd->fs_FileReq->fr_File, MODE_NEWFILE))) goto quit;
  819.         Write(file, &S16header, sizeof S16header);
  820.       }
  821.       break;
  822.   }
  823.  
  824.   // Everything set up. Tell Master we're alive and healthy.
  825.   Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_MasterSignal);
  826.  
  827.   for(;;)
  828.   {
  829.     signals = SetSignal(0L,0L);
  830.     if(signals & (SIGBREAKF_CTRL_C | 1L<<dd->fs_SlaveSignal))
  831.     {
  832.       break;
  833.     }
  834.  
  835.     if(signals & (1L<<dd->fs_EnableSignal | 1L<<dd->fs_DisableSignal) == 1L<<dd->fs_DisableSignal)
  836.     {
  837.       Wait(1L<<dd->fs_EnableSignal);
  838.     }
  839.  
  840.     CallHookPkt(AudioCtrl->ahiac_PlayerFunc, AudioCtrl, NULL);
  841.     CallHookPkt(AudioCtrl->ahiac_MixerFunc, AudioCtrl, dd->fs_MixBuffer);
  842.  
  843.     samples = AudioCtrl->ahiac_BuffSamples;
  844.  
  845.     if(AudioCtrl->ahiac_Flags & AHIACF_STEREO)
  846.     {
  847.       samples <<= 1;
  848.     }
  849.  
  850. // Search for loudest part in sample
  851.     if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
  852.     {
  853.       for(i = 0; i < samples; i++)
  854.         if(abs(((LONG *)dd->fs_MixBuffer)[i]) > maxVolume)
  855.           maxVolume = abs(((LONG *)dd->fs_MixBuffer)[i]);
  856.     }
  857.     else
  858.     {
  859.       for(i = 0; i< samples; i++)
  860.         if(abs(((WORD *)dd->fs_MixBuffer)[i]) > maxVolume)
  861.           maxVolume = abs(((WORD *)dd->fs_MixBuffer)[i]);
  862.     }
  863.  
  864.     if((AudioCtrl->ahiac_Flags & AHIACF_STEREO) && dd->fs_Format == FORMAT_S16)
  865.     {
  866.       samples >>= 1;  // Two buffers instead
  867.     }
  868.  
  869.     if(offset+samples >= dd->fs_SaveBufferSize)
  870.     {
  871.       if(Write(file, dd->fs_SaveBuffer, bytesInBuffer) != bytesInBuffer)
  872.       {
  873.         break;
  874.       }
  875.       if(file2 != NULL) {
  876.         if(Write(file2, dd->fs_SaveBuffer2, bytesInBuffer) != bytesInBuffer)
  877.         {
  878.           break;
  879.         }
  880.       }
  881.       offset = 0;
  882.       bytesInBuffer = 0;
  883.     }
  884.  
  885.     switch(dd->fs_Format)
  886.     {
  887.       case FORMAT_8SVX:
  888.         if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
  889.         {
  890.           BYTE *dest = &((BYTE *) dd->fs_SaveBuffer)[offset];
  891.           LONG *source = dd->fs_MixBuffer;
  892.  
  893.           for(i = 0; i < samples; i++)
  894.             *dest++ = *source++ >> 24;
  895.         }
  896.         else
  897.         {
  898.           BYTE *dest = &((BYTE *) dd->fs_SaveBuffer)[offset];
  899.           WORD *source = dd->fs_MixBuffer;
  900.  
  901.           for(i = 0; i < samples; i++)
  902.             *dest++ = *source++ >> 8;
  903.         }
  904.         length = samples;
  905.         break;
  906.  
  907.       case FORMAT_AIFF:
  908.       case FORMAT_AIFC:
  909.         if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
  910.         {
  911.           WORD *dest = &((WORD *) dd->fs_SaveBuffer)[offset];
  912.           LONG *source = dd->fs_MixBuffer;
  913.  
  914.           for(i = 0; i < samples; i++)
  915.           {
  916.             *dest++ = *source++ >> 16;
  917.           }
  918.         }
  919.         else
  920.         {
  921.           WORD *dest = &((WORD *) dd->fs_SaveBuffer)[offset];
  922.           WORD *source = dd->fs_MixBuffer;
  923.  
  924.           for(i = 0; i < samples; i++)
  925.           {
  926.             *dest++ = *source++;
  927.           }
  928.         }
  929.         length = samples*2;
  930.         break;
  931.  
  932.       case FORMAT_S16:
  933.         switch(AudioCtrl->ahiac_Flags & (AHIACF_HIFI | AHIACF_STEREO))
  934.         {
  935.           case 0:
  936.           {
  937.             WORD *dest = &((WORD *) dd->fs_SaveBuffer)[offset];
  938.             WORD *source = dd->fs_MixBuffer;
  939.  
  940.             for(i = 0; i < samples; i++)
  941.             {
  942.               *dest++ = *source++;
  943.             }
  944.  
  945.             length = i*2;
  946.             break;
  947.           }
  948.  
  949.           case AHIACF_STEREO:
  950.           {
  951.             WORD *dest1 = &((WORD *) dd->fs_SaveBuffer)[offset];
  952.             WORD *dest2 = &((WORD *) dd->fs_SaveBuffer2)[offset];
  953.             WORD *source = dd->fs_MixBuffer;
  954.  
  955.             for(i = 0; i < samples; i++)
  956.             {
  957.               *dest1++ = *source++;
  958.               *dest2++ = *source++;
  959.             }
  960.  
  961.             length = i*2;
  962.             break;
  963.           }
  964.  
  965.           case AHIACF_HIFI:
  966.           {
  967.             WORD *dest = &((WORD *) dd->fs_SaveBuffer)[offset];
  968.             LONG *source = dd->fs_MixBuffer;
  969.  
  970.             for(i = 0; i < samples; i++)
  971.             {
  972.               *dest++ = *source++ >> 16;
  973.             }
  974.  
  975.             length = i*2;
  976.             break;
  977.           }
  978.  
  979.           case (AHIACF_HIFI | AHIACF_STEREO):
  980.           {
  981.             WORD *dest1 = &((WORD *) dd->fs_SaveBuffer)[offset];
  982.             WORD *dest2 = &((WORD *) dd->fs_SaveBuffer2)[offset];
  983.             LONG *source = dd->fs_MixBuffer;
  984.  
  985.             for(i = 0; i < samples; i++)
  986.             {
  987.               *dest1++ = *source++ >> 16;
  988.               *dest2++ = *source++ >> 16;
  989.             }
  990.  
  991.             break;
  992.           }
  993.         }
  994.  
  995.         length = samples*2;
  996.         break;
  997.     }
  998.  
  999.     offset          += samples;
  1000.     samplesWritten  += AudioCtrl->ahiac_BuffSamples;
  1001.     bytesWritten    += length;
  1002.     bytesInBuffer   += length;
  1003.  
  1004.   }
  1005.  
  1006.   Write(file, dd->fs_SaveBuffer, bytesInBuffer);
  1007.   if(file2 != NULL)
  1008.   {
  1009.     Write(file2, dd->fs_SaveBuffer2, bytesInBuffer);
  1010.   }
  1011.  
  1012.   switch(dd->fs_Format)
  1013.   {
  1014.     case FORMAT_8SVX:
  1015.       EIGHTSVXheader.FORMsize = sizeof(EIGHTSVXheader)-8+bytesWritten;
  1016.       EIGHTSVXheader.VHDRchunk.oneShotHiSamples = samplesWritten;
  1017.       EIGHTSVXheader.VHDRchunk.samplesPerSec = AudioCtrl->ahiac_MixFreq;
  1018.       EIGHTSVXheader.BODYsize = bytesWritten;
  1019.       if(bytesWritten & 1)
  1020.         FPutC(file,'\0');   // Pad to even
  1021.       Seek(file,0,OFFSET_BEGINNING);
  1022.       Write(file,&EIGHTSVXheader,sizeof EIGHTSVXheader);
  1023.       break;
  1024.  
  1025.     case FORMAT_AIFF:
  1026.       AIFFheader.FORMsize = sizeof(AIFFheader)-8+bytesWritten;
  1027.       AIFFheader.COMMchunk.numChannels = (AudioCtrl->ahiac_Flags & AHIACF_STEREO ? 2 : 1);
  1028.       AIFFheader.COMMchunk.numSampleFrames = samplesWritten;
  1029.       ulong2extended(AudioCtrl->ahiac_MixFreq,&AIFFheader.COMMchunk.sampleRate);
  1030.       AIFFheader.SSNDsize = sizeof(SampledSoundHeader)+bytesWritten;
  1031.       Seek(file,0,OFFSET_BEGINNING);
  1032.       Write(file,&AIFFheader,sizeof AIFFheader);
  1033.       break;
  1034.  
  1035.     case FORMAT_AIFC:
  1036.       AIFCheader.FORMsize = sizeof(AIFCheader)-8+bytesWritten;
  1037.       AIFCheader.COMMchunk.numChannels = (AudioCtrl->ahiac_Flags & AHIACF_STEREO ? 2 : 1);
  1038.       AIFCheader.COMMchunk.numSampleFrames = samplesWritten;
  1039.       ulong2extended(AudioCtrl->ahiac_MixFreq,&AIFCheader.COMMchunk.sampleRate);
  1040.       AIFCheader.SSNDsize = sizeof(SampledSoundHeader)+bytesWritten;
  1041.       Seek(file,0,OFFSET_BEGINNING);
  1042.       Write(file,&AIFCheader,sizeof AIFCheader);
  1043.       break;
  1044.  
  1045.     case FORMAT_S16:
  1046.       S16header.S16F_RATE = AudioCtrl->ahiac_MixFreq;
  1047.       S16header.S16F_SAMPLES0 =
  1048.       S16header.S16F_SAMPLES1 = samplesWritten;
  1049.       S16header.S16F_SAMPLES2 = samplesWritten - 1;
  1050.       if (file2 == NULL)
  1051.       {
  1052.         S16header.S16F_PAN = S16_PAN_MID;
  1053.       }
  1054.       else
  1055.       {
  1056.         S16header.S16F_PAN = S16_PAN_LEFT;
  1057.       }
  1058.  
  1059.       Seek(file, 0, OFFSET_BEGINNING);
  1060.       Write(file, &S16header, sizeof S16header);
  1061.       if(file2 != NULL)
  1062.       {
  1063.         S16header.S16F_PAN = S16_PAN_RIGHT;
  1064.         Seek(file2,0,OFFSET_BEGINNING);
  1065.         Write(file2, &S16header, sizeof S16header);
  1066.       }
  1067.       break;   
  1068.   }
  1069.  
  1070.   if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
  1071.     maxVolume >>=16;
  1072.  
  1073.   if(maxVolume != 0)
  1074.   {
  1075.     EasyRequest(NULL, &req, NULL, 3276800/maxVolume,
  1076.       AudioCtrl->ahiac_MixFreq<frequency[FREQUENCIES-1] ? ",\nincrease the mixing frequency " : "\n");
  1077.   }
  1078.  
  1079. quit:
  1080.   if(file)
  1081.   {
  1082.     Close(file);
  1083.   }
  1084.   if(file2)
  1085.   {
  1086.     Close(file2);
  1087.   }
  1088.   if(lock)
  1089.   {
  1090.     CurrentDir(cd);
  1091.     UnLock(lock);
  1092.   }
  1093.   Forbid();
  1094.   dd->fs_SlaveTask = NULL;
  1095.   FreeSignal(dd->fs_DisableSignal);
  1096.   FreeSignal(dd->fs_EnableSignal);
  1097.   FreeSignal(dd->fs_SlaveSignal);
  1098.   dd->fs_DisableSignal  = -1;
  1099.   dd->fs_EnableSignal   = -1;
  1100.   dd->fs_SlaveSignal    = -1;
  1101.   // Tell the Master we're dying
  1102.   Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_MasterSignal);
  1103.   // Multitaking will resume when we are dead.
  1104. }
  1105.  
  1106. /*
  1107. ** Apple's 80-bit SANE extended has the following format:
  1108.  
  1109.  1       15      1            63
  1110. +-+-------------+-+-----------------------------+
  1111. |s|       e     |i|            f                |
  1112. +-+-------------+-+-----------------------------+
  1113.   msb        lsb   msb                       lsb
  1114.  
  1115. The value v of the number is determined by these fields as follows:
  1116. If 0 <= e < 32767,              then v = (-1)^s * 2^(e-16383) * (i.f).
  1117. If e == 32767 and f == 0,       then v = (-1)^s * (infinity), regardless of i.
  1118. If e == 32767 and f != 0,       then v is a NaN, regardless of i.
  1119. */
  1120.  
  1121. void ulong2extended (ULONG in, extended *ex)
  1122. {
  1123.   ex->exponent = 31+16383;
  1124.   ex->mantissa[1] = 0;
  1125.   while(!(in & 0x80000000))
  1126.   {
  1127.     ex->exponent--;
  1128.     in <<= 1;
  1129.   }
  1130.   ex->mantissa[0] = in;
  1131. }
  1132.  
  1133.  
  1134.  
  1135. /*
  1136. ** The record slave process
  1137. */
  1138.  
  1139. void __asm __saveds RecSlaveTask(register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
  1140. // RecSlaveEntry() will set up register a2 and a6 for us.
  1141. {
  1142.   ULONG   signals;
  1143.   BPTR    lock = NULL,cd,file = NULL;
  1144.   Object *o = NULL;
  1145.   BYTE   *samples = NULL;
  1146.   ULONG   length = NULL;
  1147.   ULONG   count = 0,offs = 0,i;
  1148.  
  1149.   struct AHIRecordMessage RecordMessage = 
  1150.   {
  1151.     AHIST_S16S,
  1152.     NULL,
  1153.     RECBUFFERSIZE
  1154.   };
  1155.  
  1156.   RecordMessage.ahirm_Buffer = dd->fs_RecBuffer;
  1157.  
  1158.   if(!(lock = Lock(dd->fs_RecFileReq->fr_Drawer,ACCESS_READ)))
  1159.     goto quit;
  1160.   cd = CurrentDir(lock);
  1161.  
  1162.   if(DataTypesBase)
  1163.   {
  1164.     if (!(o = NewDTObject (dd->fs_RecFileReq->fr_File,
  1165.         DTA_GroupID,GID_SOUND,
  1166.         TAG_DONE)))
  1167.       goto quit;
  1168.  
  1169.     GetDTAttrs(o,
  1170.       SDTA_Sample,&samples,
  1171.       SDTA_SampleLength,&length,
  1172.       TAG_DONE);
  1173.   }
  1174.   else // datatypes.library not open. Open the selected file as raw 8 bit signed instead.
  1175.   {
  1176.     if(!(file = Open(dd->fs_RecFileReq->fr_File,MODE_OLDFILE)))
  1177.       goto quit;
  1178.     Seek(file,0,OFFSET_END);
  1179.     length = Seek(file,0,OFFSET_BEGINNING);
  1180.     if(!(samples = AllocVec(length,MEMF_ANY)))
  1181.       goto quit;
  1182.     if(length != Read(file,samples,length))
  1183.       goto quit;
  1184.   }
  1185.  
  1186.   if(!samples || !length )
  1187.     goto quit;
  1188.  
  1189.   if((dd->fs_RecSlaveSignal = AllocSignal(-1)) == -1)
  1190.     goto quit;
  1191.  
  1192. // Everything set up. Tell Master we're alive and healthy.
  1193.     Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_RecMasterSignal);
  1194.  
  1195.     for(;;)
  1196.     {
  1197.       signals = SetSignal(0L,0L);
  1198.       if(signals & (SIGBREAKF_CTRL_C | 1L<<dd->fs_RecSlaveSignal))
  1199.         break;
  1200.  
  1201.       for(;;)
  1202.       {
  1203.         if(count+RECBUFFERSIZE-offs < length)
  1204.         {
  1205. // End of sample will not be reached; just fill to the end of dd->fs_RecBuffer.
  1206.           for(i = RECBUFFERSIZE-offs;i>0;i--)
  1207.           {
  1208.             dd->fs_RecBuffer[(offs)<<1] = 
  1209.             dd->fs_RecBuffer[((offs++)<<1)+1] = 
  1210.             samples[count++]<<8;
  1211.           }
  1212.           offs = 0;
  1213.           break;
  1214.         }
  1215.         else
  1216.         {
  1217. // End of sample will be reached. Fill part of buffer, and iterate (== don't break).
  1218.           for(i = length-count;i>0;i--)
  1219.           {
  1220.             dd->fs_RecBuffer[(offs)<<1] = 
  1221.             dd->fs_RecBuffer[((offs++)<<1)+1] = 
  1222.             samples[count++]<<8;
  1223.           }
  1224.           count = 0;
  1225.         }
  1226.  
  1227.       }
  1228.  
  1229.       CallHookPkt(AudioCtrl->ahiac_SamplerFunc,AudioCtrl,&RecordMessage);
  1230.       Delay(50*RECBUFFERSIZE/AudioCtrl->ahiac_MixFreq);
  1231.     }
  1232.  
  1233. quit:
  1234. // Get rid of object
  1235.   if(DataTypesBase)
  1236.   {
  1237.     if(o)
  1238.       DisposeDTObject (o);
  1239.   }
  1240.   else // datatypes.library not open.
  1241.   {
  1242.     if(samples)
  1243.       FreeVec(samples);
  1244.     if(file)
  1245.       Close(file);
  1246.   }
  1247.   CurrentDir(cd);
  1248.   if(lock)
  1249.     UnLock(lock);
  1250.  
  1251.   Forbid();
  1252.   dd->fs_RecSlaveTask = NULL;
  1253.   FreeSignal(dd->fs_RecSlaveSignal);
  1254.   dd->fs_RecSlaveSignal = -1;
  1255.   // Tell the Master we're dying
  1256.   Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_RecMasterSignal);
  1257.   // Multitaking will resume when we are dead.
  1258. }
  1259.